﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using Styx.WoWInternals.WoWObjects;
using Styx.Logic.Pathing;
using Styx;
using Styx.WoWInternals;
using Styx.WoWInternals.World;

namespace FelMaster.Dev
{
    public partial class AreaDebugger : Form
    {
        private static AreaDebugger instance = new AreaDebugger();

        public static void Display()
        {
            if (instance == null || instance.IsDisposed)
                instance = new AreaDebugger();
            if (!instance.Visible)
                instance.Show();
        }

        private AreaDebugger()
        {
            InitializeComponent();

            this.Resize += new System.EventHandler(this.OnResize);
            this.Paint += new System.Windows.Forms.PaintEventHandler(this.OnPaint);
        }

        public bool ShowUnits = true;
        public bool ShowPlayers = true;
        public bool ShowLocalPlayer = true;

        private LocalPlayer Me { get { return StyxWoW.Me; } }

        private float WoWRadius = 60f;

        private Brush RedBrush = new SolidBrush(Color.Red);
        private Brush BlueBrush = new SolidBrush(Color.Blue);
        private Brush GreenBrush = new SolidBrush(Color.Green);
        private Brush CyanBrush = new SolidBrush(Color.Cyan);
        private Brush YellowBrush = new SolidBrush(Color.Yellow);

        private Pen RedPen = new Pen(Color.Red, 1f);
        private Pen BluePen = new Pen(Color.Blue, 1f);
        private Pen GreenPen = new Pen(Color.Green, 1f);
        private Pen CyanPen = new Pen(Color.Cyan, 1f);
        private Pen YellowPen = new Pen(Color.Yellow, 1f);

        private Brush PlayerRangeBrush = new SolidBrush(Color.FromArgb(0x44, Color.Cyan));

        private Brush LoS_NACK_Brush = new SolidBrush(Color.FromArgb(0x22, Color.Red));

        private void FillCircle(Graphics gBmp, int x, int y, int radius, Brush brush)
        {
            gBmp.FillEllipse(brush, x - radius, y - radius, radius * 2, radius * 2);
        }
        private void DrawCircle(Graphics gBmp, int x, int y, int radius, Pen pen)
        {
            gBmp.DrawEllipse(pen, x - radius, y - radius, radius * 2, radius * 2);
        }
        private void DrawCross(Graphics gBmp, int x, int y, int radius, Pen pen)
        {
            gBmp.DrawLine(pen, x - radius, y - radius, x + radius, y + radius);
            gBmp.DrawLine(pen, x + radius, y - radius, x - radius, y + radius);
        }
        private Point Game2Bitmap(WoWPoint point)
        {
            var P = new Point(0, 0);

            var myPos = Me.Location;
            var dx = point.X - myPos.X;
            var dy = point.Y - myPos.Y;

            P.X = (int)(this.ClientRectangle.Width / 2 + dx / WoWRadius * this.ClientRectangle.Width / 2);
            P.Y = (int)(this.ClientRectangle.Height / 2 + dy / WoWRadius * this.ClientRectangle.Height / 2);

            return P;
        }

        private void DrawLocalPlayer(Graphics gBmp)
        {
            var p = Game2Bitmap(Me.Location);
            FillCircle(gBmp, p.X, p.Y, 5, CyanBrush);
        }

        private void DrawUnit(Graphics gBmp, WoWUnit unit)
        {
            var p = Game2Bitmap(unit.Location);
            var brush = YellowPen;
            if (unit.IsFriendly)
                brush = GreenPen;
            else if (unit.IsHostile)
                brush = RedPen;

            DrawCircle(gBmp, p.X, p.Y, 3, brush);

            if (unit.Guid == Me.CurrentTargetGuid)
                DrawCross(gBmp, p.X, p.Y, 3, CyanPen);
        }
        private void DrawPlayer(Graphics gBmp, WoWPlayer unit)
        {
            var p = Game2Bitmap(unit.Location);
            var brush = YellowBrush;
            if (unit.IsFriendly)
                brush = GreenBrush;
            else if (unit.IsHostile)
                brush = RedBrush;

            FillCircle(gBmp, p.X, p.Y, 3, brush);

            if (unit.Guid == Me.CurrentTargetGuid)
                DrawCross(gBmp, p.X, p.Y, 3, CyanPen);
        }

        private void DrawLoS(Graphics gBmp)
        {
            var center = Me.Location;
            var step = 2f;

            for (var x = center.X - WoWRadius; x <= center.X + WoWRadius; x += step)
            {
                for (var y = center.Y - WoWRadius; y <= center.Y + WoWRadius; y += step)
                {
                    var point = new WoWPoint(x, y, center.Z);
                    if (point.Distance2D(center) > 40f+2*step)
                    {
                        continue;
                    }
                    Navigator.FindHeight(x, y, out point.Z);
                    if (!GameWorld.IsInLineOfSightOCD(center, point))
                    {
                        var rectCenter = Game2Bitmap(point);
                        var rectSize = step / WoWRadius * this.ClientRectangle.Width / 2;
                        gBmp.FillRectangle(LoS_NACK_Brush, rectCenter.X - rectSize / 2, rectCenter.Y - rectSize / 2, rectSize, rectSize);
                    }
                }
            }
        }

        private void OnPaint(object sender, System.Windows.Forms.PaintEventArgs e)
        {
            ObjectManager.Update();

            Graphics gForm = e.Graphics;
            gForm.FillRectangle(Brushes.Black, this.ClientRectangle);

            var W = this.ClientRectangle.Width;
            var H = this.ClientRectangle.Height;

            // Create a Bitmap image in memory and set its CompositingMode
            Bitmap bmp = new Bitmap(W, H, PixelFormat.Format32bppArgb);
            Graphics gBmp = Graphics.FromImage(bmp);
            gBmp.CompositingMode = CompositingMode.SourceCopy;

            //draw range, axis, etc.
            FillCircle(gBmp, W / 2, H / 2, (int)(40f / WoWRadius /2f * W), PlayerRangeBrush);
            DrawLoS(gBmp);

            //draw me
            DrawLocalPlayer(gBmp);

            //draw units
            var units = ObjectManager.GetObjectsOfType<WoWUnit>(true, false).Where(x => x.Distance2DSqr <= WoWRadius * WoWRadius);
            foreach (var x in units)
            {
                if (x.IsPlayer)
                    DrawPlayer(gBmp, x.ToPlayer());
                else
                    DrawUnit(gBmp, x);
            }

            // draw the bitmap on our window
            gForm.DrawImage(bmp, 0, 0, bmp.Width, bmp.Height);
            bmp.Dispose();
            gBmp.Dispose();
        }

        private void OnResize(object sender, System.EventArgs e)
        {
            Invalidate();
        }
    }
}
